package com.flyduck.mall.oms.h5.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.flyduck.mall.cms.api.RemoteCartItemService;
import com.flyduck.mall.oms.api.constant.OrderConstant;
import com.flyduck.mall.oms.dto.CartItemDTO;
import com.flyduck.mall.oms.domain.OmsOrder;
import com.flyduck.mall.oms.domain.OmsOrderItem;
import com.flyduck.mall.oms.domain.OmsRefund;
import com.flyduck.mall.oms.h5.service.H5OrderService;
import com.flyduck.mall.oms.h5.vo.*;
import com.flyduck.mall.oms.manager.CmsCartItemManager;
import com.flyduck.mall.oms.manager.OmsOrderManager;
import com.flyduck.mall.oms.manager.GenerateSnManager;
import com.flyduck.mall.oms.mapper.OmsOrderItemMapper;
import com.flyduck.mall.oms.mapper.OmsOrderMapper;
import com.flyduck.mall.oms.mapper.OmsRefundMapper;
import com.flyduck.mall.oms.mq.MqSender;

import com.flyduck.mall.common.core.utils.BeanUtils;
import com.flyduck.mall.common.mybatis.utils.PageUtils;
import com.flyduck.ss.common.core.exception.ServiceException;

import com.flyduck.mall.pms.api.RemoteProductService;
import com.flyduck.mall.pms.api.RemoteSkuStockService;
import com.flyduck.mall.pms.api.vo.RemoteProductRespVO;
import com.flyduck.mall.pms.api.vo.RemoteProductUpdateReqVO;
import com.flyduck.mall.pms.api.vo.RemoteSkuStockReduceReqVO;
import com.flyduck.mall.pms.api.vo.RemoteSkuStockReleaseReqVO;
import com.flyduck.mall.ums.api.RemoteAddressService;
import com.flyduck.mall.ums.api.vo.RemoteAddressRespVO;
import com.flyduck.ss.common.satoken.utils.LoginHelper;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @program: vueshop
 * @description:
 * @author: flyduck
 * @create: 2024-05-20 20:45
 **/
@Service
public class H5OrderServiceImpl implements H5OrderService {
    @Resource
    private OmsOrderManager omsOrderManager;
    @Resource
    private OmsOrderMapper omsOrderMapper;
    @Resource
    private OmsOrderItemMapper omsOrderItemMapper;
    @DubboReference
    private RemoteSkuStockService remoteSkuStockService;
    @Resource
    private MqSender mqSender;
    @Resource
    private OmsRefundMapper omsRefundMapper;
    @Resource
    private GenerateSnManager generateSnManager;
    @Resource
    private CmsCartItemManager cmsCartItemManager;
    @DubboReference
    private RemoteAddressService remoteAddressService;
    @DubboReference
    private RemoteProductService remoteProductService;
    @DubboReference
    private RemoteCartItemService remoteCartItemService;


    /**
     * 购物车购买、立即购买的订单预览
     * @param h5OrderPreviewReqVO
     * @return
     */
    @Override
    public H5OrderPreviewRespVO previewOrder(H5OrderPreviewReqVO h5OrderPreviewReqVO) {
        Long userId = LoginHelper.getUserId();
        //判断参数是否完整
        if(
                CollectionUtil.isEmpty(h5OrderPreviewReqVO.getCartIds())
                        &&
                (h5OrderPreviewReqVO.getProductId() == null || h5OrderPreviewReqVO.getSkuId() == null || h5OrderPreviewReqVO.getQuantity() == null)
        ){
            throw new ServiceException("参数不完整");
        }

        //获取收货地址
        //addressId为空，展示默认收货地址，如果没有默认收货地址，则不展示
        //addressId不为空，根据addressId获取收货地址
        RemoteAddressRespVO remoteAddressRespVO;
        if (h5OrderPreviewReqVO.getAddressId() == null) {
            remoteAddressRespVO = remoteAddressService.getDefaultAddressByUserId(userId);
        }else {
            remoteAddressRespVO = remoteAddressService.getAddressById(h5OrderPreviewReqVO.getAddressId());
            if(!userId.equals(remoteAddressRespVO.getUserId())){
                throw new ServiceException("配送地址异常");
            }
        }

        //获取购物车的商品/立即购买的商品
        List<CartItemDTO> cartItemList = cmsCartItemManager.getCartItemList(h5OrderPreviewReqVO.getCartIds(),
                userId,
                h5OrderPreviewReqVO.getProductId(),
                h5OrderPreviewReqVO.getSkuId(),
                h5OrderPreviewReqVO.getQuantity());

        //计算总金额：价格 * 数量
        BigDecimal totalAmount = cartItemList.stream()
                .map(
                        cartItem -> cartItem.getPrice().multiply(
                                new BigDecimal(cartItem.getQuantity())
                        )
                ).reduce(BigDecimal.ZERO, BigDecimal::add);


        //优惠劵、运费等信息
        BigDecimal freight = new BigDecimal("0");
        totalAmount = totalAmount.add(freight);

        H5OrderPreviewRespVO h5OrderPreviewRespVO = new H5OrderPreviewRespVO();
        H5OrderPreviewRespVO.AppAddressVO appAddressVO = BeanUtils.toBean(remoteAddressRespVO, H5OrderPreviewRespVO.AppAddressVO.class);
        h5OrderPreviewRespVO.setAddress(appAddressVO);
        List<H5OrderPreviewRespVO.AppCartItemVO> appCartItemVOS = BeanUtils.toBeanList(cartItemList, H5OrderPreviewRespVO.AppCartItemVO.class);
        h5OrderPreviewRespVO.setCartItems(appCartItemVOS);
        h5OrderPreviewRespVO.setTotalAmount(totalAmount);
        h5OrderPreviewRespVO.setFreight(freight);
        return h5OrderPreviewRespVO;
    }



    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public String createOrder(H5OrderCreateReqVO h5OrderCreateReqVO) {

        Long userId = LoginHelper.getUserId();


        // 判断收货地址
        RemoteAddressRespVO remoteAddressRespVO = remoteAddressService.getAddressById(h5OrderCreateReqVO.getAddressId());
        if(remoteAddressRespVO == null || !userId.equals(remoteAddressRespVO.getUserId())){
            throw new ServiceException("收货地址异常");
        }


        //获取购物车的商品/立即购买的商品
        List<CartItemDTO> cartItemList = cmsCartItemManager.getCartItemList(h5OrderCreateReqVO.getCartIds(),
                userId,
                h5OrderCreateReqVO.getProductId(),
                h5OrderCreateReqVO.getSkuId(),
                h5OrderCreateReqVO.getQuantity());


        //计算总金额：价格 * 数量
        BigDecimal total = cartItemList.stream()
                .map(
                        cartItem -> cartItem.getPrice().multiply(
                                new BigDecimal(cartItem.getQuantity())
                        )
                ).reduce(BigDecimal.ZERO, BigDecimal::add);
        //优惠劵、运费等信息
        BigDecimal freight = new BigDecimal("0");
        total = total.add(freight);

        // 创建订单记录
        OmsOrder omsOrder = new OmsOrder();
        omsOrder.setUserId(userId);
        omsOrder.setSn(generateSnManager.generateOrderSn());

        omsOrder.setTotalAmount(total);
        omsOrder.setFreight(freight);

        //收货人信息
        omsOrder.setReceiverName(remoteAddressRespVO.getName());
        omsOrder.setReceiverTel(remoteAddressRespVO.getTel());
        omsOrder.setReceiverAddress(remoteAddressRespVO.getProvince() + remoteAddressRespVO.getCity() + remoteAddressRespVO.getCounty() + remoteAddressRespVO.getAddressDetail());
        omsOrder.setReceiverPostalCode(remoteAddressRespVO.getPostalCode());
        omsOrder.setReceiverAreaCode(remoteAddressRespVO.getAreaCode());

        omsOrder.setOrderStatus(OrderConstant.OrderStatus.PENDING_PAYMENT.getCode());
        omsOrder.setCreateTime(new Date());
        omsOrder.setNote(h5OrderCreateReqVO.getNote());
        omsOrderMapper.insert(omsOrder);


        // 保存商品信息快照
        List<OmsOrderItem> omsOrderItemList = new ArrayList<>();
        for (CartItemDTO cartItemDTO : cartItemList) {
            OmsOrderItem omsOrderItem = new OmsOrderItem();
            omsOrderItem.setProductId(cartItemDTO.getProductId());
            omsOrderItem.setProductName(cartItemDTO.getProductName());
            omsOrderItem.setProductImage(cartItemDTO.getProductImage());
            omsOrderItem.setProductSn(cartItemDTO.getProductSn());
            omsOrderItem.setCategoryId(cartItemDTO.getCategoryId());
            omsOrderItem.setPrice(cartItemDTO.getPrice());
            omsOrderItem.setQuantity(cartItemDTO.getQuantity());

            omsOrderItem.setSkuId(cartItemDTO.getSkuId());
            omsOrderItem.setSku(cartItemDTO.getSku());

            omsOrderItem.setOrderId(omsOrder.getId());
            omsOrderItem.setCreateTime(new Date());

            omsOrderItemList.add(omsOrderItem);
        }
        omsOrderItemMapper.insertOrUpdate(omsOrderItemList);

        // 删除购物车的商品信息
        remoteCartItemService.deleteByIds(h5OrderCreateReqVO.getCartIds());

        // 判断库存并扣减库存
        List<RemoteSkuStockReduceReqVO> remoteSkuStockReduceReqVOList = BeanUtils.toBeanList(omsOrderItemList, RemoteSkuStockReduceReqVO.class);
        remoteSkuStockService.batchReduceSkuStock(remoteSkuStockReduceReqVOList);

        // 超时未支付则自动取消订单 - 死信队列
        mqSender.sendCancelOrderMessage(omsOrder.getId());

        return omsOrder.getSn();

    }

    @Override
    public H5OrderTotalCountRespVO getOrderTotalCount() {
        Long userId = LoginHelper.getUserId();

        List<OmsOrder> omsOrderList = omsOrderMapper.selectList(
                new LambdaQueryWrapper<OmsOrder>()
                        .eq(OmsOrder::getUserId, userId)
        );

        //PENDING_PAYMENT(0, "待付款"),
        //PENDING_DELIVERY(1, "待发货"),
        //PENDING_RECEIPT(2, "待收货"),
        //COMPLETED(3, "已完成"),
        //CANCELLED(4, "已取消"),
        //REFUND_REQUESTED(5, "申请退款"),
        //REFUNDED(6, "已退款"),
        //REFUND_FAILED(7, "退款失败");
        int unPay = 0;//待付款
        int unDeli = 0;//待发货
        int unDecv = 0;//待收货
        int unRefund = 0;//退款中
        long unComment = 0;//待评论

        //订单状态：0->待付款；1->待发货；2->待收货；3-已完成；4->已取消；5-申请退款，6->已退款，7->退款失败
        //页面展示：待付款、待发货、待收货、待评论（几种商品有几个）、退款中
        for (OmsOrder omsOrder : omsOrderList) {
            if (OrderConstant.OrderStatus.PENDING_PAYMENT.getCode() == omsOrder.getOrderStatus()) {
                unPay++;
            }else if(OrderConstant.OrderStatus.PENDING_DELIVERY.getCode() == omsOrder.getOrderStatus()){
                unDeli++;
            }else if(OrderConstant.OrderStatus.PENDING_RECEIPT.getCode() == omsOrder.getOrderStatus()){
                unDecv++;
            }else if(OrderConstant.OrderStatus.REFUND_REQUESTED.getCode() == omsOrder.getOrderStatus()){
                unRefund++;
            }
        }

        //已完成状态的所有订单id
        List<Long> completedOrderIds = omsOrderList.stream()
                .filter(appOrder -> OrderConstant.OrderStatus.COMPLETED.getCode() == appOrder.getOrderStatus())
                .map(OmsOrder::getId)
                .collect(Collectors.toList());

        if (CollectionUtil.isNotEmpty(completedOrderIds)) {
            unComment = omsOrderItemMapper.selectCount(
                    new LambdaQueryWrapper<OmsOrderItem>()
                            .in(OmsOrderItem::getOrderId, completedOrderIds)
                            .isNull(OmsOrderItem::getCommentId)
            );
        }

        H5OrderTotalCountRespVO h5OrderTotalCountRespVO = new H5OrderTotalCountRespVO();
        h5OrderTotalCountRespVO.setUnPay(unPay);
        h5OrderTotalCountRespVO.setUnDeli(unDeli);
        h5OrderTotalCountRespVO.setUnDecv(unDecv);
        h5OrderTotalCountRespVO.setUnRefund(unRefund);
        h5OrderTotalCountRespVO.setUnComment(unComment);
        return h5OrderTotalCountRespVO;
    }

    @Override
    public Page<H5OrderRespVO> getOrderPageByStatus(Page page, Integer status) {
        Long userId = LoginHelper.getUserId();

        Page<OmsOrder> orderPage = omsOrderMapper.selectPage(
                page,
                new LambdaQueryWrapper<OmsOrder>()
                        .eq(OmsOrder::getUserId, userId)
                        .eq(status != null, OmsOrder::getOrderStatus, status)
                        .orderByDesc(OmsOrder::getCreateTime)
        );
        Page<H5OrderRespVO> appOrderRespVOPage = PageUtils.convert(orderPage, H5OrderRespVO.class);
        for (H5OrderRespVO h5OrderRespVO : appOrderRespVOPage.getRecords()) {
            List<OmsOrderItem> omsOrderItemList = omsOrderItemMapper.getAppOrderItemListByOrderId(h5OrderRespVO.getId());
            List<H5OrderRespVO.OmsOrderItemVO> appOrderItemVOS = BeanUtils.toBeanList(omsOrderItemList, H5OrderRespVO.OmsOrderItemVO.class);
            h5OrderRespVO.setOrderItems(appOrderItemVOS);
        }

        return appOrderRespVOPage;
    }

    @Override
    public H5OrderDetailsRespVO getOrderDetailsById(Long orderId) {
        OmsOrder omsOrder = omsOrderManager.verifyAppOrderById(orderId);
        H5OrderDetailsRespVO h5OrderDetailsRespVO = BeanUtils.toBean(omsOrder, H5OrderDetailsRespVO.class);

        List<OmsOrderItem> omsOrderItemList = omsOrderItemMapper.getAppOrderItemListByOrderId(orderId);
        List<H5OrderDetailsRespVO.OmsOrderItemVO> appOrderItemVOS = BeanUtils.toBeanList(omsOrderItemList, H5OrderDetailsRespVO.OmsOrderItemVO.class);

        h5OrderDetailsRespVO.setOrderItems(appOrderItemVOS);

        //申请退款、已退款的订单加上退款的信息
        if (Arrays.asList(OrderConstant.OrderStatus.REFUND_REQUESTED.getCode(),OrderConstant.OrderStatus.REFUNDED.getCode()).contains(omsOrder.getOrderStatus())) {
            //退款单
            OmsRefund omsRefund = omsRefundMapper.selectOne(
                    new LambdaQueryWrapper<OmsRefund>()
                            .eq(OmsRefund::getOrderId, h5OrderDetailsRespVO.getId())
            );
            H5OrderDetailsRespVO.OmsRefundVO appRefundVO = BeanUtils.toBean(omsRefund, H5OrderDetailsRespVO.OmsRefundVO.class);
            h5OrderDetailsRespVO.setAppRefund(appRefundVO) ;
        }
        return h5OrderDetailsRespVO;
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void cancelOrderById(Long orderId) {
        OmsOrder omsOrder = omsOrderManager.verifyAppOrderById(orderId);

        if(OrderConstant.OrderStatus.PENDING_PAYMENT.getCode() != omsOrder.getOrderStatus()){
            throw new ServiceException("无法取消该订单");
        }

        //释放商品库存
        List<OmsOrderItem> omsOrderItemList = omsOrderItemMapper.getAppOrderItemListByOrderId(orderId);
        List<RemoteSkuStockReleaseReqVO> remoteSkuStockReleaseReqVOList = BeanUtils.toBeanList(omsOrderItemList, RemoteSkuStockReleaseReqVO.class);
        remoteSkuStockService.batchReleaseSkuStock(remoteSkuStockReleaseReqVOList);

        //更新订单状态为已取消
        omsOrder.setOrderStatus(OrderConstant.OrderStatus.CANCELLED.getCode());
        omsOrder.setCompleteTime(new Date());
        omsOrder.setUpdateTime(new Date());
        omsOrderMapper.updateById(omsOrder);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void deleteById(Long orderId) {
        OmsOrder omsOrder = omsOrderManager.verifyAppOrderById(orderId);
        //PENDING_PAYMENT(0, "待付款"),
        //PENDING_DELIVERY(1, "待发货"),
        //PENDING_RECEIPT(2, "待收货"),
        //COMPLETED(3, "已完成"),
        //CANCELLED(4, "已取消"),
        //REFUND_REQUESTED(5, "申请退款"),
        //REFUNDED(6, "已退款"),
        //REFUND_FAILED(7, "退款失败");
        if (!Arrays.asList(
                OrderConstant.OrderStatus.PENDING_PAYMENT.getCode(),
                OrderConstant.OrderStatus.COMPLETED.getCode(),
                OrderConstant.OrderStatus.CANCELLED.getCode(),
                OrderConstant.OrderStatus.REFUNDED.getCode()
        ).contains(omsOrder.getOrderStatus())) {
            throw new ServiceException("无法删除该订单");
        }

        // 待付款订单 => 取消、释放库存
        if (OrderConstant.OrderStatus.PENDING_PAYMENT.getCode() == omsOrder.getOrderStatus()) {
            List<OmsOrderItem> omsOrderItemList = omsOrderItemMapper.getAppOrderItemListByOrderId(orderId);

            List<RemoteSkuStockReleaseReqVO> remoteSkuStockReleaseReqVOList = BeanUtils.toBeanList(omsOrderItemList, RemoteSkuStockReleaseReqVO.class);
            remoteSkuStockService.batchReleaseSkuStock(remoteSkuStockReleaseReqVOList);

            omsOrder.setOrderStatus(OrderConstant.OrderStatus.CANCELLED.getCode());
            omsOrder.setCompleteTime(new Date());
            omsOrder.setUpdateTime(new Date());
            omsOrderMapper.updateById(omsOrder);
        }

        omsOrderMapper.deleteById(orderId);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void confirmOrderById(Long orderId) {
        OmsOrder omsOrder = omsOrderManager.verifyAppOrderById(orderId);

        if (OrderConstant.OrderStatus.PENDING_RECEIPT.getCode() != omsOrder.getOrderStatus()) {
            throw new ServiceException("该订单无法确定收货");
        }

        // 更新商品销量
        List<RemoteProductUpdateReqVO> remoteProductUpdateReqVOList = new ArrayList<>();
        List<OmsOrderItem> omsOrderItemList = omsOrderItemMapper.getAppOrderItemListByOrderId(orderId);
        for (OmsOrderItem omsOrderItem : omsOrderItemList) {
            RemoteProductRespVO productRespVO = remoteProductService.getProductById(omsOrderItem.getProductId());

            RemoteProductUpdateReqVO remoteProductUpdateReqVO = new RemoteProductUpdateReqVO();
            remoteProductUpdateReqVO.setId(productRespVO.getId());
            remoteProductUpdateReqVO.setSale(productRespVO.getSale() + omsOrderItem.getQuantity());
            remoteProductUpdateReqVOList.add(remoteProductUpdateReqVO);
        }
        remoteProductService.batchUpdateProduct(remoteProductUpdateReqVOList);

        // 更新订单状态为完成
        omsOrder.setOrderStatus(OrderConstant.OrderStatus.COMPLETED.getCode());
        omsOrder.setReceiveTime(new Date());
        omsOrder.setUpdateTime(new Date());
        omsOrderMapper.updateById(omsOrder);
    }


}
